#pragma once
#include <stdio.h>
#include <iostream>
#include <string>
#include <mutex>
#include <vector>
#include <utility>
#include <unordered_map>
#include "connector/include/mysql.h"
#include "./log/log.hpp"
#include "MysqlPool.hpp"

#define HOST "localhost"
#define USERNAME "root"
#define PASSWORD "Bit104-7274"
#define SOCKET "/var/lib/mysql/mysql.sock"
const std::string client_table ="account";
const std::string admin_table ="admin";
const std::string user_table = "user";
const std::string repair_table = "repair";
const std::string pay_table = "pay"; 

#define NOEXIST 0  // 账号不存在
#define EXIST 1    // 账号存在
#define SQLERROR 2 // 执行sql语句出错
#define ADD_Y 3    // 注册账号成功

typedef std::unordered_map<std::string,std::string> Info;
typedef std::vector<std::vector<std::pair<std::string,std::string>>> Data;
//多态，client和admin分别调用各自的方法
class Object       
{
public:
   virtual int query (MYSQL *mysql,Info &result){}; //result 输出型参数
   virtual int insert (MYSQL *mysql){};
};
class user : public Object
{
   private:
   std::string name;
   std::string addr;
   std::string tele;
   std::string login;
};
class client : public Object
{
public:
   client(const std::string&name,const std::string&password,const std::string&login="2023-04-17")
      :login_(login)
      ,name_(name)
      ,password_(password)
      {}
   //查询是否存在该用户,同时获得信息
   int query(MYSQL*mysql,Info &result)
   {
      const std::string sql= "select *from "+client_table+" where name="+"'"+name_+"'";
      if(mysql_query(mysql,sql.c_str())==0)
      {  
         MYSQL_RES *res = mysql_store_result(mysql);
         MYSQL_RES res_bak = *res; //拷贝结果
         //判断查询结果
         if( mysql_fetch_row(res)== nullptr)
         {
            return NOEXIST;
         }
         else
         {
            //获得列表字段名称
            MYSQL_FIELD * field;
            std::vector<std::string> column_name;
            while (field = mysql_fetch_field(res))
            {
               column_name.push_back(std::string(field->name));
            }
            //每一行
            MYSQL_ROW row;
            while( row = mysql_fetch_row(&res_bak))
            {
               for(int i=0;i<column_name.size();i++)
               {
                  result.emplace(column_name[i],row[i]);
               }
            }
         }
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
      return EXIST;
   }

   int insert(MYSQL*mysql)
   {
      const std::string sql="insert into " + client_table + "(rank,name,password) values(" 
      + "'" + login_ + "'" + "," + "'" + name_ + "'" +"," + "'" + password_ + "'" +")";

      if(mysql_query(mysql,sql.c_str())==0)
      {
         LOG(NOTICE,"添加账号 "+name_+" 成功");
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
      return ADD_Y;
   }
private:
   std::string login_;    // login-time
   std::string name_;     // username
   std::string password_; // password
};

class admin : public Object
{
public:
   admin(const std::string&rank,const std::string&name,const std::string&password)
      :rank_(rank)
      ,name_(name)
      ,password_(password)
      {}
   //查询是否存该管理员
   int query(MYSQL*mysql,Info &result)
   {
      const std::string sql= "select *from "+admin_table+" where name="+"'"+name_+"'";
      if(mysql_query(mysql,sql.c_str())==0)
      {  
         MYSQL_RES *res= mysql_store_result(mysql);
         MYSQL_RES res_bak = *res; //拷贝结果
         //判断查询结果
         if( mysql_fetch_row(res) == nullptr)
         {
            return NOEXIST;
         }
         else
         {
            //获得列表字段名称
            MYSQL_FIELD * field;
            std::vector<std::string> column_name;
            while (field = mysql_fetch_field(res))
            {
               column_name.push_back(std::string(field->name));
            }
            //每一行
            MYSQL_ROW row ;
            while( row = mysql_fetch_row(&res_bak))
            {
               for(int i=0;i<column_name.size();i++)
               {
                  result.emplace(column_name[i],row[i]);
               }
            }
         }
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
      return EXIST;
   }
   int insert(MYSQL*mysql)
   {
      const std::string sql="insert into " + admin_table + "(`rank`,name,password) values(" 
      + "'" + rank_ + "'" + "," + "'" + name_ + "'" +"," + "'" + password_ + "'" +")";
      
      if(mysql_query(mysql,sql.c_str())==0)
      {
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
      return ADD_Y;
   }
private:
   std::string rank_;
   std::string name_;
   std::string password_;
};

class Manager
{
private:
   static Manager *instance;// Manager对象单例 
   static MysqlPool * mysqlPool; // MYSQL连接池单例
   static std::mutex mtx_;

private:
   Manager (){};
   Manager (const Manager&)=delete;
   Manager operator =(const Manager & )=delete;

public:
   // 创建manager单例
   static Manager *GetInstance()
   {  
      if(instance == nullptr)
      {
         mtx_.lock();
         if(instance == nullptr)
         {
            instance = new Manager();
         }
         mtx_.unlock();
      }
      return instance;
   }
   // 创建MYSQL连接池单例
   static MYSQL *GetMYSQL()
   {
      if (mysql_ == nullptr)
      {
         mtx_.lock();
         if (mysql_ == nullptr)
         {
            mysql_ = new MYSQL();
         }
         mtx_.unlock();
      }
      return mysql_;
   }

   // 初始化mysql服务
   bool init(const std::string &database)
   {
      GetMYSQL();
      mysql_init(mysql_);
      mysql_options(mysql_, MYSQL_SET_CHARSET_NAME, "utf8mb3");
      // 连接数据库
      if (mysql_real_connect(mysql_, HOST, USERNAME, PASSWORD, database.c_str(), 0, SOCKET, 0))
      {
         LOG(NOTICE,"connect to "+database +" success");
      }
      else
      {
         LOGERR("connect to "+database+" error");
         return false;
      }
      return true;
   }

   // 查询用户注册信息
   int Query(Object *obj,Info &result) 
   {
      return obj->query(mysql_,result);
   }

   //注册添加用户
   int AddUser(Object *obj)
   {
      Info result;
      int status =Query(obj,result);
      if(status == NOEXIST)
      {
         return obj->insert(mysql_);
      }
      else if(status == EXIST)
      {
         return EXIST;
      }
      else{
         return SQLERROR;
      }
   }

   int GetUserData( Data &output)
   {
      const std::string sql = "select *from " + user_table ;
      if (mysql_query(mysql_,sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(mysql_);
         MYSQL_RES res_bak = *res; //拷贝结果
         //判断查询结果
         if( mysql_fetch_row(res)== nullptr)
         {
            return NOEXIST;
         }
         else
         {
            //获得列表字段名称
            MYSQL_FIELD * field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            //每一行
            MYSQL_ROW row;
            while( row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string,std::string>> row_data;
               for(int i=0;i<Column_name.size();i++)
               {
                  row_data.push_back (make_pair(Column_name[i],row[i]) );
               }
               output.push_back(std::move(row_data));
            }
            return EXIST;
         }
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
   }

   bool DelUserData (const std::string &addr)
   {
      const std::string sql = "delete from " + user_table + " where addr = " + "'" + addr + "'";
      if (mysql_query(mysql_,sql.c_str()) == 0)
      {
         return true;
      }
      else
      {
         LOGERR(sql+" error");
         return false;
      }
   }

   bool AddUserData (std::vector<std::string> info)
   {
      const std::string sql = "insert into " + user_table + 
      " values(" + "'" +info[0] + "'" + "," + "'" + info[1] +"'" + "," +"'" +info[2] +"'" + "," + "'" +info[3] + "'" +")";
      if(mysql_query(mysql_,sql.c_str())==0)
      {
         return true;
      }
      else{
         LOGERR(sql+" error");
         return false;
      }
   }

   int GetPayList(Data &output)
   {
      const std::string sql = "select *from " + pay_table ;
      if (mysql_query(mysql_,sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(mysql_);
         MYSQL_RES res_bak = *res; //拷贝结果
         //判断查询结果
         if( mysql_fetch_row(res)== nullptr)
         {
            return NOEXIST;
         }
         else
         {
            //获得列表字段名称
            MYSQL_FIELD * field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            //每一行
            MYSQL_ROW row;
            while( row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string,std::string>> row_data;
               for(int i=0;i<Column_name.size();i++)
               {
                  row_data.push_back (make_pair(Column_name[i],row[i]) );
               }
               output.push_back(std::move(row_data));
            }
            return EXIST;
         }
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
   }

   bool AddPayData (std::vector<std::string> info)
   {
      const std::string sql = "insert into " + pay_table + 
      " values(" + "'" +info[0] + "'" + "," + "'" + info[1] +"'" + "," +"'" +info[2] +"'" + "," + "'" +info[3] + "'" +")";
      if(mysql_query(mysql_,sql.c_str())==0)
      {
         return true;
      }
      else{
         LOGERR(sql+" error");
         return false;
      }
   }

   bool DelPayData(const std::string &addr)
   {
      const std::string sql = "delete from " + pay_table + " where addr = " + "'" + addr + "'";
      if (mysql_query(mysql_,sql.c_str()) == 0)
      {
         return true;
      }
      else
      {
         LOGERR(sql+" error");
         return false;
      }
   }

   int GetRepairList(Data &output)
   {
      const std::string sql = "select *from " + repair_table ;
      if (mysql_query(mysql_,sql.c_str()) == 0)
      {
         MYSQL_RES *res = mysql_store_result(mysql_);
         MYSQL_RES res_bak = *res; //拷贝结果
         //判断查询结果
         if( mysql_fetch_row(res)== nullptr)
         {
            return NOEXIST;
         }
         else
         {
            //获得列表字段名称
            MYSQL_FIELD * field;
            std::vector<std::string> Column_name;
            while (field = mysql_fetch_field(res))
            {
               Column_name.push_back(std::string(field->name));
            }
            //每一行
            MYSQL_ROW row;
            while( row = mysql_fetch_row(&res_bak))
            {
               std::vector<std::pair<std::string,std::string>> row_data;
               for(int i=0;i<Column_name.size();i++)
               {
                  row_data.push_back (make_pair(Column_name[i],row[i]) );
               }
               output.push_back(std::move(row_data));
            }
            return EXIST;
         }
      }
      else
      {
         LOGERR(sql+" error");
         return SQLERROR;
      }
   }

   bool DelRepairData(const std::string &addr)
   {
      const std::string sql = "delete from " + repair_table + " where addr = " + "'" + addr + "'";
      if (mysql_query(mysql_,sql.c_str()) == 0)
      {
         return true;
      }
      else
      {
         LOGERR(sql+" error");
         return false;
      }
   }

   bool AddRepairData (std::vector<std::string> info)
   {
      const std::string sql = "insert into " + repair_table + 
      " values(" + "'" +info[0] + "'" + "," + "'" + info[1] +"'" + "," +"'" +info[2] +"'" + "," + "'" +info[3] + "'" +")";
      if(mysql_query(mysql_,sql.c_str())==0)
      {
         return true;
      }
      else{
         LOGERR(sql+" error");
         return false;
      }
   }

   ~Manager()
   {
      mysql_close(mysql_);
   }
};
Manager * Manager::instance=nullptr;
MYSQL *Manager::mysql_ = nullptr;
std::mutex Manager::mtx_;